#include "preHeader.h"
#include "ActivityObjectMgr.h"
#include "Session/MapServerSession.h"

ActivityObjectMgr::ActivityObjectMgr()
{
}

ActivityObjectMgr::~ActivityObjectMgr()
{
}

GErrorCode ActivityObjectMgr::OnUpdateActivityObjectPosition(INetPacket& pck)
{
	bool isAdd;
	ObjGUID objGuid;
	uint32 entry;
	InstGUID instGuid;
	vector3f pos;
	pck >> isAdd >> objGuid >> entry >> instGuid;
	if (!pck.IsReadableEmpty()) {
		pck >> pos;
	}

	auto actObjType = ObjectType2ActObjType(OBJECT_TYPE(objGuid.TID));
	auto& actObjPosList = m_actObjPos[(int)actObjType][entry];
	if (isAdd) {
		actObjPosList.push_back({objGuid, instGuid, pos});
	} else {
		auto itr = std::find_if(actObjPosList.begin(), actObjPosList.end(),
			[=](const ActObjPos& actObjPos) {
			return actObjPos.instGuid == instGuid &&
				actObjPos.objGuid == objGuid;
		});
		if (itr != actObjPosList.end()) {
			actObjPosList.erase(itr);
		}
	}
	return CommonSuccess;
}

GErrorCode ActivityObjectMgr::OnQueryActivityObjectPosition(INetPacket& pck,
	MapServerSession *pSession, const RPCActor::RequestMetaInfo &info) const
{
	int32 objType;
	uint32 entry;
	InstGUID instGuid;
	pck >> objType >> entry >> instGuid;

	NetPacket rpcRespPck(GS_RPC_INVOKE_RESP);
	size_t anchor = rpcRespPck.Placeholder(false);
	auto actObjType = ObjectType2ActObjType(OBJECT_TYPE(objType));
	auto& actObjPosTypeList = m_actObjPos[(int)actObjType];
	auto itr = actObjPosTypeList.find(entry);
	if (itr != actObjPosTypeList.end()) {
		auto pActObjPos = FilterBestActObjPos(itr->second, instGuid);
		if (pActObjPos != NULL) {
			rpcRespPck.Put(anchor, true);
			rpcRespPck << pActObjPos->instGuid << pActObjPos->pos;
		}
	}
	pSession->RPCReply(rpcRespPck, info.sn);

	return CommonSuccess;
}

const ActivityObjectMgr::ActObjPos* ActivityObjectMgr::FilterBestActObjPos(
	const std::vector<ActObjPos>& actObjPosList, InstGUID instGuid)
{
	if (actObjPosList.empty()) {
		return NULL;
	}

	std::vector<const ActObjPos*> priorActObjPosList[3];
	for (auto& actObjPos : actObjPosList) {
		if (actObjPos.instGuid == instGuid) {
			priorActObjPosList[0].push_back(&actObjPos);
			continue;
		}
		if (!priorActObjPosList[0].empty()) {
			continue;
		}
		if (actObjPos.instGuid.MAPID == instGuid.MAPID &&
			actObjPos.instGuid.TID == instGuid.TID) {
			priorActObjPosList[1].push_back(&actObjPos);
			continue;
		}
		if (!priorActObjPosList[1].empty()) {
			continue;
		}
		if (actObjPos.instGuid.MAPID == instGuid.MAPID) {
			priorActObjPosList[2].push_back(&actObjPos);
			continue;
		}
	}

	for (auto& actObjPosList : priorActObjPosList) {
		if (!actObjPosList.empty()) {
			return actObjPosList[System::Rand(0, (int)actObjPosList.size())];
		}
	}

	return &actObjPosList[System::Rand(0, (int)actObjPosList.size())];
}

ActivityObjectMgr::ActObjType ActivityObjectMgr::ObjectType2ActObjType(OBJECT_TYPE objType)
{
	switch (objType) {
	case TYPE_STATICOBJECT:
		return ActObjType::StaticObject;
	case TYPE_CREATURE:
		return ActObjType::Creature;
	default:
		assert(false && "can't reach here.");
		return ActObjType::None;
	}
}
